﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UtilsBase.Error
{
    /// <summary>
    /// HTTP中间件
    /// </summary>
    public class HttpMiddleware
    {
        /// <summary>
        /// 请求委托
        /// </summary>
        private readonly RequestDelegate _next;
        /// <summary>
        /// 日志
        /// </summary>
        private readonly ILogger _logger;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="next"></param>
        /// <param name="logger"></param>
        public HttpMiddleware(RequestDelegate next, ILogger<HttpMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }
        /// <summary>
        /// 异步调用
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task InvokeAsync(HttpContext context)
        {
            #region Request信息
            // 判断请求类型
            if (context.Request.Method == "GET")
            {
                // 取得请求数据
                string queryString = context.Request.QueryString.Value;
                // 日志
                string outMsg = string.Format("Method: {0}, Host: {1}, Path: {2}, QueryString: {3}",
                    context.Request.Method,
                    context.Request.Host,
                    context.Request.Path,
                    queryString);
                // 输出
                _logger.LogInformation(outMsg);
            }
            else
            {
                // 开启数据缓存
                context.Request.EnableBuffering();
                using (MemoryStream memoryStream = new())
                {
                    // 复制Body数据到缓存
                    await context.Request.Body.CopyToAsync(memoryStream);
                    context.Request.Body.Position = 0;
                    using (StreamReader streamReader = new(memoryStream))
                    {
                        // 读取Body数据
                        string body = await streamReader.ReadToEndAsync();
                        // 日志
                        string outMsg = string.Format("Method: {0}, Host: {1}, Path: {2}, Request body: {3}",
                            context.Request.Method,
                            context.Request.Host,
                            context.Request.Path,
                            body);
                        // 输出
                        _logger.LogInformation(outMsg);
                    }
                }
            }
            #endregion
            #region Response信息
            // 原Body缓存
            Stream originalBody = context.Response.Body;
            try
            {
                // 新Body缓存
                using (MemoryStream memoryStream = new())
                {
                    // Body赋值为新Body缓存
                    context.Response.Body = memoryStream;
                    // 向下执行（等待返回）
                    await _next.Invoke(context);
                    // 原Body缓存赋值为新Body缓存
                    memoryStream.Position = 0;
                    await memoryStream.CopyToAsync(originalBody);
                    using (StreamReader streamReader = new(memoryStream))
                    {
                        // 读取Body数据
                        memoryStream.Position = 0;
                        string body = await streamReader.ReadToEndAsync();
                        // 日志
                        string outMsg = string.Format("Method: {0}, Host: {1}, Path: {2}, Response body: {3}",
                            context.Request.Method,
                            context.Request.Host,
                            context.Request.Path,
                            body);
                        // 输出
                        _logger.LogInformation(outMsg);
                    }
                }
            }
            finally
            {
                // Body重新赋值为原始Body缓存
                context.Response.Body = originalBody;
            }
            #endregion
        }
    }
}
